iT邦幫忙

2022 iThome 鐵人賽

DAY 11
1

「上次的遞迴題目,如果想通的話,那這次我們來試看看這一題」70. Climbing Stairs

「這題不是跟 509. Fibonacci Number 差不多嗎」兩人開始合作寫出

class Solution {
    fun climbStairs(n: Int): Int {
        return when {
            n == 0 -> 0
            n == 1 -> 1
            n == 2 -> 2
            else -> climbStairs(n-1) + climbStairs(n-2)
        }
    }
}

送出答案之後,第一次看到「Time Limit Exceeded」的兩人,開始面面相覷,不太知道該怎麼處理才好。

「對了!菁菁你上次教過我,可以看錯誤的資料是哪一筆」

Last executed input: 45

「沒錯!這一題的輸入比起之前的題目要大,所以之前的寫法沒法直接通過喔」夏天看了看兩人的解答之後說。

「如果要通過這一題,其中一個方法是放棄使用遞迴的寫法,改成使用迴圈」

class Solution {
    fun climbStairs(n: Int): Int {
        if (n <= 2) {
            return n
        }
        var result = 0
        var n1 = 1
        var n2 = 2
        (3..n).forEach { _ ->
            result = n1 + n2
            n1 = n2
            n2 = result
        }
        return result
    }
}

「原來迴圈也可以這樣寫!又學到一個新寫法囉」兩人驚訝的說。

「除了這個寫法之外,還可以使用一個叫做尾遞迴的概念。

尾遞迴簡單的說,就是遞迴的位置只有在整個函數的最尾端,呼叫函數自身。這樣的遞迴方式,可以讓編譯器做一些特殊處理,讓整個程式速度更快。

在 Kotlin 裡面,要宣告一個尾遞迴的函數,可以用 tailrec 這個關鍵字」

class Solution {
    fun climbStairs(n: Int): Int {
        return climbStairsRec(n, 1, 1)
    }

    private tailrec fun climbStairsRec(n: Int, first: Int, second: Int): Int {
        return when (n) {
            1 -> second
            else -> climbStairsRec(n - 1, second, first + second)
        }
    }
}

「哇⋯⋯這個我要想一下」曉欣拿出紙筆,開始思考這樣的遞迴為什麼會跟原本的方式有一樣的答案。

「沒問題,曉欣你這種拿出紙筆思考的習慣很好,很多工程師即便工作很長時間,都還是習慣嘗試用腦袋直接去想演算法。這樣的習慣其實很容易出錯。用紙筆不僅可以減少出錯的機會,同時也讓跟其他人的討論更加方便。」

「今天的觀念比較難一點點,就先讓兩位看看吧」


上一篇
Day 10:開始遞迴:771、58、509
下一篇
Day 12:合作無間的兩人:1929、1480、1672
系列文
Kotlin 程式人:Leetcode 意外旅程30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言